package com.hzw.saas.service.rss.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.hzw.saas.api.rss.IJournalCustomService;
import com.hzw.saas.api.rss.IJournalUserSubService;
import com.hzw.saas.api.rss.IRssEsService;
import com.hzw.saas.api.rss.bo.JournalArticleNoticeBO;
import com.hzw.saas.api.rss.bo.JournalCustomBO;
import com.hzw.saas.api.rss.bo.JournalUserSubBO;
import com.hzw.saas.api.rss.query.JournalArticleSearchQuery;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.util.MapperUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service("rssEsService")
@RequiredArgsConstructor
public class RssEsServiceImpl implements IRssEsService {

    private static final String [] INDICES = { "rss" };

    private final RestHighLevelClient restHighLevelClient;

    @Resource(name = "journalUserSubService")
    private IJournalUserSubService journalUserSubService;

    @Resource()
    private IJournalCustomService journalCustomService;

    private BoolQueryBuilder searchBuilder(JournalArticleSearchQuery searchQuery, String userId) {
        // 构造Rss-ids条件
        BoolQueryBuilder boolQueryRootBuilder = buildRssIdsCondition(userId);
        if (boolQueryRootBuilder == null) return null;
        // 构造指定条件
        buildCommonCondition(searchQuery, boolQueryRootBuilder);
        // 关键字条件构造
        buildKeyWordCondition(searchQuery, boolQueryRootBuilder);
        return boolQueryRootBuilder;
    }

    private BoolQueryBuilder buildRssIdsCondition(String userId) {
        BoolQueryBuilder boolQueryRootBuilder = QueryBuilders.boolQuery();
        // RSS-ID
        if (StrUtil.isNotBlank(userId)) {
            //查询用户所有的站点
            List<String> allJournalByUser = journalCustomService.findAllJournalByUser(userId);
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                if (CollectionUtil.isNotEmpty(allJournalByUser)) {
                    allJournalByUser.forEach(rssId -> {
                            if (StrUtil.isBlank(rssId)) {
                                return;
                            }
                            boolQueryBuilder.should(QueryBuilders.termQuery("rssId", rssId));
                        });
                    // 有没有构造Rss-Id条件，没有则返回空
                    if (!boolQueryBuilder.hasClauses()) {
                        return null;
                    }
                    boolQueryRootBuilder.must(boolQueryBuilder);
                }

        }
        return boolQueryRootBuilder;
    }

    private void buildCommonCondition(JournalArticleSearchQuery searchQuery, BoolQueryBuilder boolQueryRootBuilder) {
        BoolQueryBuilder journalIssBuilder = QueryBuilders.boolQuery();
        List<String> journalIss = searchQuery.getJournalIss();
        if (CollectionUtil.isNotEmpty(journalIss)) {
            journalIss.forEach(iss -> {
                if (StrUtil.isBlank(iss)) {
                    return;
                }
                journalIssBuilder.should(QueryBuilders.wildcardQuery("journalIssn", "*".concat(iss).concat("*")));
            });
            boolQueryRootBuilder.must(journalIssBuilder);
        }
        // 分类编号
        BoolQueryBuilder catalogIdsBuilder = QueryBuilders.boolQuery();
        List<String> catalogIds = searchQuery.getCatalogIds();
        if (CollectionUtil.isNotEmpty(catalogIds)) {
            catalogIds.forEach(catalogId -> {
                if (StrUtil.isBlank(catalogId)) {
                    return;
                }
                catalogIdsBuilder.should(QueryBuilders.termQuery("catalogId", catalogId));
            });
            boolQueryRootBuilder.must(catalogIdsBuilder);
        }
        // 期刊名称
        BoolQueryBuilder journalNamesBuilder = QueryBuilders.boolQuery();
        List<String> journalName = searchQuery.getJournalName();
        if (CollectionUtil.isNotEmpty(journalName)) {
            journalName.forEach(name -> {
                if (StrUtil.isBlank(name)) {
                    return;
                }
                journalNamesBuilder.should(QueryBuilders.matchQuery("journalName", name).operator(Operator.AND));
            });
            boolQueryRootBuilder.must(journalNamesBuilder);
        }
        // 文章标题
        BoolQueryBuilder titlesBuilder = QueryBuilders.boolQuery();
        List<String> titles = searchQuery.getTitles();
        if (CollectionUtil.isNotEmpty(titles)) {
            titles.forEach(title -> {
                if (StrUtil.isBlank(title)) {
                    return;
                }
                titlesBuilder.should(QueryBuilders.matchQuery("title", title).operator(Operator.AND));
            });
            boolQueryRootBuilder.must(titlesBuilder);
        }
        // 作者
        BoolQueryBuilder authorsBuilder = QueryBuilders.boolQuery();
        List<String> authors = searchQuery.getAuthors();
        if (CollectionUtil.isNotEmpty(authors)) {
            authors.forEach(author -> {
                if (StrUtil.isBlank(author)) {
                    return;
                }
                authorsBuilder.should(QueryBuilders.wildcardQuery("authors", author.concat("*")));
            });
            boolQueryRootBuilder.must(authorsBuilder);
        }
        // 时间段
        BoolQueryBuilder pubDateBuilder = QueryBuilders.boolQuery();
        Date pubStartDate = searchQuery.getPubStartDate();
        Date pubEndDate = searchQuery.getPubEndDate();
        if (Objects.nonNull(pubEndDate) && Objects.nonNull(pubStartDate)) {
            pubDateBuilder.should(QueryBuilders.rangeQuery("pubDate")
                .gte(DateUtil.format(pubStartDate, DatePattern.UTC_SIMPLE_PATTERN))
                .lte(DateUtil.format(pubEndDate, DatePattern.UTC_SIMPLE_PATTERN)));
            boolQueryRootBuilder.must(pubDateBuilder);
        }
    }

    private void buildKeyWordCondition(JournalArticleSearchQuery searchQuery, BoolQueryBuilder boolQueryRootBuilder) {
        List<String> keyWords = searchQuery.getKeyWords();
        if (CollectionUtil.isNotEmpty(keyWords)) {
            BoolQueryBuilder boolQueryOtherBuilder = QueryBuilders.boolQuery();
            keyWords.forEach(keyWord ->
                boolQueryOtherBuilder
                    .should(QueryBuilders.matchQuery("journalName", keyWord).operator(Operator.AND))
                    .should(QueryBuilders.matchQuery("title", keyWord).operator(Operator.AND))
                    .should(QueryBuilders.matchQuery("description", keyWord).operator(Operator.AND))
                    .should(QueryBuilders.wildcardQuery("authors", keyWord.concat("*")))
            );
            boolQueryRootBuilder.must(boolQueryOtherBuilder);
        }
    }


    @Override
    public List<JournalArticleNoticeBO> findAll(){
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(new BoolQueryBuilder());
        sourceBuilder.from(0);
        sourceBuilder.size(1000);
        SearchRequest request = new SearchRequest();
        request.source(sourceBuilder);
        request.indices(INDICES);
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es检索失败", e);
        }
        SearchHits hits = searchResponse.getHits();
        TotalHits totalHits = hits.getTotalHits();
        //为了防止空指针
        int s = 0;
        s= (int) (totalHits.value/1000);
        List<JournalArticleNoticeBO> journalArticleNotices1 = new ArrayList<>();
        //查询前s*1000
        for (int i=0;i<s;i++){
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(new BoolQueryBuilder());
            searchSourceBuilder.from(s*1000);
            searchSourceBuilder.size(s*1000+1000);
            SearchRequest searchRequest = new SearchRequest();
            request.source(searchSourceBuilder);
            request.indices(INDICES);
            SearchResponse response = null;
            try {
                response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            } catch (Exception e) {
                log.error("es检索失败", e);
            }
            SearchHits hits1 = response.getHits();
            SearchHit[] searchHits = hits1.getHits();
            List<JournalArticleNoticeBO> journalArticleNotices = new ArrayList<>();
            for (SearchHit searchHit : searchHits) {
                Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
                JournalArticleNoticeBO journalArticleNotice = BeanUtil.fillBeanWithMap(sourceAsMap, new JournalArticleNoticeBO(), true);
                journalArticleNotices.add(journalArticleNotice);
            }
            journalArticleNotices1.addAll(journalArticleNotices);
        }

       return MapperUtil.nf().mapAsList(journalArticleNotices1,JournalArticleNoticeBO.class);
    }

    @Override
    public List<JournalArticleNoticeBO> findByJournalId(String journalId,Integer size){
        BoolQueryBuilder boolQueryRootBuilder = QueryBuilders.boolQuery();
        boolQueryRootBuilder.must(QueryBuilders.termQuery("rssId", journalId));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryRootBuilder);
        sourceBuilder.from(0);
        sourceBuilder.size(size);
        SearchRequest request = new SearchRequest();
        request.source(sourceBuilder);
        request.indices(INDICES);
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es检索失败", e);
        }
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        List<JournalArticleNoticeBO> journalArticleNotices = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
            JournalArticleNoticeBO journalArticleNotice = BeanUtil.fillBeanWithMap(sourceAsMap, new JournalArticleNoticeBO(), true);
            journalArticleNotices.add(journalArticleNotice);
        }
        return MapperUtil.nt().mapAsList(journalArticleNotices,JournalArticleNoticeBO.class);
    }

    @Override
    public List<JournalArticleNoticeBO> findArticle(JournalArticleSearchQuery journalArticleSearchParam, PageParam pageParam, String userId) {
        if (pageParam == null) {
            pageParam = new PageParam();
        }
        if (pageParam.getCurrent() <= 0) {
            pageParam.setCurrent(1);
        }

        // 构建检索条件
        BoolQueryBuilder boolQueryBuilder = searchBuilder(journalArticleSearchParam, userId);
        if (Objects.isNull(boolQueryBuilder)) {
            // 为空直接返回
            pageParam.setTotal(0);
            return new ArrayList<>();
        }
        // 构建es检索请求
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.from((int) (pageParam.getCurrent() - 1) * (int) pageParam.getSize());
        sourceBuilder.size((int) pageParam.getSize());
        SearchRequest request = new SearchRequest();
        request.source(sourceBuilder);
        request.indices(INDICES);
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es检索失败", e);
        }
        SearchHits hits = searchResponse.getHits();
        TotalHits totalHits = hits.getTotalHits();
        pageParam.setTotal(totalHits.value);
        SearchHit[] searchHits = hits.getHits();
        List<JournalArticleNoticeBO> journalArticleNotices = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
            JournalArticleNoticeBO journalArticleNotice = BeanUtil.fillBeanWithMap(sourceAsMap, new JournalArticleNoticeBO(), true);
            journalArticleNotices.add(journalArticleNotice);
        }
        return journalArticleNotices;
    }

}
